package com.chuangke.common.utils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.chuangke.common.exception.ChuangkeException;

/**
 * 反射相关辅助方法
 * 
 * @author chuangke
 * @date Aug 19, 2018
 */
public class ReflectionUtils {

	/**
	 * 根据方法名调用指定对象的方法
	 * 
	 * @param object 要调用方法的对象
	 * @param method 要调用的方法名
	 * @param args   参数对象数组
	 * @return
	 */
	public static Object invoke(Object object, String method, Object... args) {
		Object result = null;
		Class<?> clazz = object.getClass();
		Method queryMethod = getMethod(clazz, method, args);
		if (queryMethod != null) {
			try {
				result = queryMethod.invoke(object, args);
			} catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e) {
				e.printStackTrace();
			}
		} else {
			try {
				throw new NoSuchMethodException(clazz.getName() + " 类中没有找到 " + method + " 方法。");
			} catch (NoSuchMethodException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	/**
	 * 根据方法名和参数对象查找方法
	 * 
	 * @param clazz
	 * @param name
	 * @param args  参数实例数据
	 * @return
	 */
	public static Method getMethod(Class<?> clazz, String name, Object[] args) {
		Method queryMethod = null;
		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			if (method.getName().equals(name)) {
				Class<?>[] parameterTypes = method.getParameterTypes();
				if (parameterTypes.length == args.length) {
					boolean isSameMethod = true;
					for (int i = 0; i < parameterTypes.length; i++) {
						Object arg = args[i];
						if (arg == null) {
							arg = "";
						}
						// !parameterTypes[i].equals(args[i].getClass()) &&
						if (!parameterTypes[i].isAssignableFrom(args[i].getClass())) {
							isSameMethod = false;
						}
					}
					if (isSameMethod) {
						queryMethod = method;
						break;
					}
				}
			}
		}
		return queryMethod;
	}

	/**
	 * 查找是否包含属性
	 * 
	 * @param object
	 * @param property
	 * @return
	 */
	public static boolean hasProperty(Object object, String property) {
		List<Field> fields = getAllField(object);

		for (Field field : fields) {
			if (field.getName().equals(property)) {
				return true;
			}
		}
		return false;
	}

	public static List<Field> getAllField(Object object) {
		Class<?> clazz = object.getClass();
		List<Field> fieldList = new ArrayList<>();
		while (clazz != Object.class) {
			fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
			clazz = clazz.getSuperclass();
		}
		return fieldList;
	}

	@SuppressWarnings("unchecked")
	public static <T> T  getInstance(String className, Object... args) {
		try {
			Class<?> clazz = Class.forName(className) ;
			return (T) getInstance(clazz,args) ;
		} catch (ClassNotFoundException e) {
			throw new ChuangkeException(e) ;
		}
	}
	
	public static <T> T  getInstance(Class<T> clazz, Object... args) {
		Class<?>[] argsClazzs = new Class<?>[args.length];
		for (int i = 0; i < args.length; i++) {
			argsClazzs[i] = args[i].getClass();
		}
		try {
			Constructor<T> constructor = clazz.getConstructor(argsClazzs);
            return constructor.newInstance(args);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
}
